package smartt.styy.auth.model.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import smartt.styy.common.constant.CommonConstants;
import smartt.styy.common.constant.RestCodeConstants;
import smartt.styy.common.exception.auth.UserTokenException;
import smartt.styy.common.util.StringHelper;

import java.text.SimpleDateFormat;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;

/**
 * @author shangtengfei
 */
@Slf4j
public class JWTHelper {
    private static RsaKeyHelper rsaKeyHelper = new RsaKeyHelper();
    
    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 密钥加密token
     *
     * @param jwtInfo
     * @param priKeyPath
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo, String priKeyPath, int expire) throws Exception {
        String compactJws = Jwts.builder()
                .setSubject(jwtInfo.getUniqueName())
                .claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
                .claim(CommonConstants.JWT_KEY_NAME, jwtInfo.getNickName())
                .claim(CommonConstants.JWT_KEY_USER_TYPES, jwtInfo.getUserTypes())
                .claim(CommonConstants.JWT_KEY_USER_TELPHONE, jwtInfo.getTelPhone())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKeyPath))
                .compact();
        return compactJws;
    }

    /**
     * 密钥加密token
     *
     * @param jwtInfo
     * @param priKey
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo, byte priKey[], int expire) throws Exception {
        String compactJws = Jwts.builder()
                .setSubject(jwtInfo.getUniqueName())
                .claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
                .claim(CommonConstants.JWT_KEY_NAME, jwtInfo.getNickName())
                .claim(CommonConstants.JWT_KEY_USER_TYPES, jwtInfo.getUserTypes())
                .claim(CommonConstants.JWT_KEY_USER_TELPHONE, jwtInfo.getTelPhone())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKey))
                .compact();
        return compactJws;
    }

    /**
     * 公钥解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Jws<Claims> parserToken(String token, String pubKeyPath) throws Exception {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKeyPath)).parseClaimsJws(token);
        return claimsJws;
    }
    /**
     * 公钥解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Jws<Claims> parserToken(String token, byte[] pubKey) throws Exception {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKey)).parseClaimsJws(token);
        return claimsJws;
    }
    /**
     * 获取token中的用户信息
     *
     * @param token
     * @param pubKeyPath
     * @return
     * @throws Exception
     */
    public static IJWTInfo getInfoFromToken(String token, String pubKeyPath) throws Exception {
    	if(StringUtils.isEmpty(token)){
        	throw new UserTokenException("当前请求token为空，无法访问！",RestCodeConstants.TOKEN_ERROR_CODE);
        }
    	Jws<Claims> claimsJws = parserToken(token, pubKeyPath);
        Claims body = claimsJws.getBody();
        return new JWTInfo(body.getSubject(), 
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_ID)), 
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_NAME)),
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_TYPES)),
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_TELPHONE)));
    }
    /**
     * 获取token中的用户信息
     *
     * @param token
     * @param pubKey
     * @return
     * @throws Exception
     */
    public static IJWTInfo getInfoFromToken(String token, byte[] pubKey) throws Exception {
        if(StringUtils.isEmpty(token)){
        	throw new UserTokenException("当前请求token为空，无法访问！",RestCodeConstants.TOKEN_ERROR_CODE);
        }
    	
    	Jws<Claims> claimsJws = parserToken(token, pubKey);
    	long jwtExp = claimsJws.getBody().getExpiration().getTime();
    	long nowMillis = System.currentTimeMillis();
    	long effectiveTime =0;
    	if(jwtExp>nowMillis){
        	effectiveTime = jwtExp - nowMillis;
        	long totalSeconds = effectiveTime / 1000;
            //求出现在的秒
            long currentSecond = totalSeconds % 60;
            
            //求出现在的分
            long totalMinutes = totalSeconds / 60;
            long currentMinute = totalMinutes % 60;
            
            //求出现在的小时
            long totalHour = totalMinutes / 60;
            long currentHour = totalHour % 24;
            //显示时间
            log.info("获取token中的用户信息，当前token："+token+"，剩余总毫秒为： " + effectiveTime+"，时分秒格式\n:"+ currentHour + ":" + currentMinute + ":" + currentSecond + " GMT");
        }
        Claims body = claimsJws.getBody();
    	return new JWTInfo(body.getSubject(), 
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_ID)), 
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_NAME)),
        		effectiveTime,
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_TYPES)),
        		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_TELPHONE)));
    }
}
